import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { FirstPersonControls } from "three/examples/jsm/controls/FirstPersonControls.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

var data = {
  scene: null, // 场景
  camera: null, // 相机
  renderer: null, // 渲染器
  modal: null, // 模型
  orbitControls: null, // 轨道控制器
  target: null, // 键盘移动目标
  dLight: null, // 灯光移动
  angle: "third" // 当前视角
};

// 初始化场景
export const mainScene = val => {
  methods.initScene();
  methods.render();
  methods.addModal();
  methods.addGrassFloor();
  document.addEventListener("keyup", e => {
    methods.onCodeMove(e.keyCode);
  });
};

// 切换视角
export const changePersonAngle = e => {
  data.angle = e;
  // 第一视角
  if (e == "first") {
    let { x, y, z } = data.target.position;
    data.camera.position.set(x - 10, 20, z);
  } else {
    data.camera.position.set(80, 50, 280);
  }
};

const methods = {
  /**
   * 初始化场景
   * 元素：场景、摄像机、渲染器
   */
  initScene() {
    const container = document.getElementById("main-canvas-box");
    // 场景
    data.scene = new THREE.Scene();
    // 摄像机
    data.camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );
    data.camera.position.set(80, 50, 280);
    data.camera.lookAt(data.scene.position);
    data.camera.updateProjectionMatrix(); // 更新投影矩阵
    // 渲染器
    data.renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    data.renderer.setClearColor("#CDE3F1", 1.0);
    data.renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild(data.renderer.domElement);
    data.renderer.shadowMap.enabled = true; // 渲染器阴影
    data.renderer.outputEncoding = THREE.sRGBEncoding; // 锐化

    // 坐标轴辅助对象
    var axes = new THREE.AxesHelper(500);
    data.scene.add(axes);

    methods.controller();
    methods.addLight();
  },

  // 轨道控制器：配合animate，不断循环渲染，达到用鼠标旋转物体的作用
  controller() {
    data.orbitControls = new OrbitControls(
      data.camera,
      data.renderer.domElement
    );
  },

  // 光源 环境光+聚光灯
  addLight() {
    // 环境光不能用来投射阴影，因为它没有方向。
    var ambienLight = new THREE.AmbientLight("#ffffff", 0.6);
    data.scene.add(ambienLight);
    // 方向光
    var directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); // 创建方向光
    directionalLight.castShadow = true; // 将平行光产生阴影的属性打开
    data.scene.add(directionalLight); // 将方向光添加到场景
    directionalLight.position.set(-40, 200, -450); // 要设置位置
    directionalLight.castShadow = true; // 设置阴影
    data.renderer.shadowMap.enabled = true;

    data.dLight = directionalLight; // 灯光跟随
  },

  // 地面
  addFloor() {
    var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
    var planeMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccc });
    var plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.rotation.x = -0.5 * Math.PI;
    plane.position.x = 15;
    plane.position.y = 0;
    plane.position.z = 0;
    data.scene.add(plane);
    plane.receiveShadow = true; // 接受阴影
  },

  // 使用草地
  addGrassFloor: () => {
    // 创建地平面并设置大小
    var textureLoader = new THREE.TextureLoader();
    var grass = require("../../../../assets/image/grass.jpg");
    var cubeMaterial = new THREE.MeshStandardMaterial({
      map: textureLoader.load(grass)
    });
    cubeMaterial.map.wrapS = THREE.RepeatWrapping;
    cubeMaterial.map.wrapT = THREE.RepeatWrapping;
    cubeMaterial.map.repeat.set(6, 6);
    var planeGeometry = new THREE.PlaneGeometry(1000, 1000);
    var plane = new THREE.Mesh(planeGeometry, cubeMaterial);

    // 设置平面位置并旋转
    plane.rotation.x = -0.5 * Math.PI;
    plane.position.y = 0;
    plane.position.z = 0;
    //是否接受阴影投射 (非常重要)
    plane.receiveShadow = true;
    data.scene.add(plane);
  },

  // 添加模型
  addModal() {
    var loader = new GLTFLoader();
    // 家
    loader.load(
      "modules/people/house/scene.gltf",
      gltf => {
        // 设置模型尺寸
        var model = gltf.scene;
        model.scale.set(8, 8, 8);
        model.position.set(0, 2, 0);
        // 模型是否否需要阴影
        gltf.scene.traverse(obj => {
          obj.castShadow = true;
          obj.receiveShadow = true;
        });

        data.scene.add(model);
      },
      undefined,
      error => {
        console.error(error);
      }
    );
    // waddles
    loader.load(
      "modules/toyStory/waddle/scene.gltf",
      gltf => {
        // 设置模型尺寸
        var model = gltf.scene;
        model.scale.set(2, 2, 2);
        model.position.set(170, 0, 150);
        // 模型是否否需要阴影
        gltf.scene.traverse(obj => {
          obj.castShadow = true;
          obj.receiveShadow = true;
        });
        data.target = model;
        data.scene.add(model);
      },
      undefined,
      error => {
        console.error(error);
      }
    );
    // MABEL
    loader.load(
      "modules/toyStory/mabel/scene.gltf",
      gltf => {
        // 设置模型尺寸
        var model = gltf.scene;
        model.scale.set(6, 6, 6);
        model.position.set(150, 1, 120);
        // 模型是否否需要阴影
        gltf.scene.traverse(obj => {
          obj.castShadow = true;
          obj.receiveShadow = true;
        });
        data.target = model;
        data.scene.add(model);
      },
      undefined,
      error => {
        console.error(error);
      }
    );
  },

  // 动起来：根据键盘控制模型移动
  onCodeMove(keyCode) {
    switch (keyCode) {
      case 87:
        data.target.position.x += 2;
        data.camera.position.x += 2;
        data.dLight.position.x += 2;
        data.target.rotation.y = Math.PI * 0.5;
        data.camera.rotation.y = -Math.PI * 0.5;
        break;
      case 83:
        data.target.position.z -= 2;
        data.camera.position.z -= 2;
        data.dLight.position.z -= 2;
        data.target.rotation.y = Math.PI;
        data.camera.rotation.y = -Math.PI;
        break;
      case 65:
        data.target.position.x -= 2;
        data.camera.position.x -= 2;
        data.dLight.position.x -= 2;
        data.target.rotation.y = Math.PI * 1.5;
        data.camera.rotation.y = -Math.PI * 1.5;
        break;
      case 68:
        data.target.position.z += 2;
        data.camera.position.z += 2;
        data.dLight.position.z += 2;
        data.target.rotation.y = Math.PI * 2;
        data.camera.rotation.y = -Math.PI * 2;
        break;
      default:
        break;
    }
  },

  // 渲染：场景可以转起来、第一人称视觉
  render() {
    data.renderer.render(data.scene, data.camera);
    requestAnimationFrame(methods.render);
  }
};
